﻿using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using UnityEngine;
namespace HurricanePackage
{
    /// <summary>
    /// 事件订阅管理
    /// </summary>
    /// <typeparam name="ENUM"></typeparam>
    public abstract class SubscribeManager<ENUM>
        where ENUM : Enum
    {
        //有参回调字典
       [NotNull] private Dictionary<ENUM, BroadcastCallBack> m_dCallBackDic;
       //无参回调字典
       [NotNull] private Dictionary<ENUM, BroadcastAction> m_dActionDic;

       [NotNull] private BroadcastActionCache m_broadcastActionCache;
       [NotNull] private BroadcastCallBackCache m_broadcastCallBackCache;

        protected SubscribeManager()
        {
            m_dActionDic = new Dictionary<ENUM, BroadcastAction>();
            m_dCallBackDic = new Dictionary<ENUM, BroadcastCallBack>();
            m_broadcastActionCache = new BroadcastActionCache();
            m_broadcastCallBackCache = new BroadcastCallBackCache();
        }

        public virtual void Discard()
        {
            m_dActionDic.Clear();
            m_dCallBackDic.Clear();
            m_broadcastCallBackCache.Discard();
            m_broadcastActionCache.Discard();
        }

#if UNITY_EDITOR
        ~SubscribeManager()
        {
            if (_HasUnregCallback())
            {
                Debug.LogError($"{DeriveName}:当消息系统被回收时，内部有没有反注册的Callback");
            }
        }
#endif

        #region 有参回调
        /// <summary>
        /// 注册有参回调
        /// </summary>
        public void RegisterMsg(ENUM _type, BroadcastCallDel _del)
        {
            //字典中要是没有该类型的事件类则添加
            if (!m_dCallBackDic.TryGetValue(_type, out var broadcastCallBack))
            {
                broadcastCallBack = new BroadcastCallBack(new List<BroadcastCallDel>());
                m_dCallBackDic[_type] = broadcastCallBack;
            }
            //添加委托,重复内存地址则忽略
            broadcastCallBack?.AddCall(_del);
        }
        /// <summary>
        /// 注销有参回调
        /// </summary>
        public void CancelMsg(ENUM _type, BroadcastCallDel _del)
        {
            //字典中无该类型事件直接返回
            if(!m_dCallBackDic.TryGetValue(_type,out var broadcastCallBack))
                return;
            broadcastCallBack?.RemoveCall(_del);
        }
        #endregion

        #region 无参回调
        /// <summary>
        /// 注册无参回调
        /// </summary>
        public void RegisterMsg(ENUM _type, Action _del)
        {
            //字典中要是没有该类型的事件类则添加
            if (!m_dActionDic.TryGetValue(_type, out var broadcastAction))
            {
                broadcastAction = new BroadcastAction(new List<Action>());
                m_dActionDic[_type] = broadcastAction;
            }
            //添加委托,重复内存地址则忽略
            broadcastAction?.AddCall(_del);
        }
        /// <summary>
        /// 注销无参回调
        /// </summary>
        public void CancelMsg(ENUM _type, Action _del)
        {
            //字典中无该类型事件直接返回
            if (!m_dActionDic.TryGetValue(_type, out var broadcastAction))
                return;
            broadcastAction?.RemoveCall(_del);
        }

        #endregion


        /// <summary>
        /// 广播消息
        /// </summary>
        /// <param name="_type"></param>
        /// <param name="_params"></param>
        public void SendMsg(ENUM _type, params object[] _params)
        {
            //处理有参回调
            if (m_dCallBackDic.TryGetValue(_type, out var srcList))
            {
                //检查该类型事件是否拥有回调,无内容直接返回
                if (srcList != null && srcList.CallCount == 0)
                    return;
                //从缓存池中获取对象作为副本
                var dealer = m_broadcastCallBackCache.PopItem();
                if (dealer == null)
                    return;
                try
                {
                    //执行回调
                    dealer.AddCall(srcList);
                    for (int i = 0; i < dealer.CallCount; i++)
                    {
                        var del = dealer[i];
                        var paramList = _params;
                        if (del == null)
                            continue;
                        if(paramList == null || paramList.Length ==0)
                            del.Invoke();
                        else
                            del.Invoke(paramList);
                    }
                }
                finally
                {
                    //将使用完的对象返回缓存池
                    m_broadcastCallBackCache.PushItem(dealer);
                }
            }
            //处理无参回调
            if (m_dActionDic.TryGetValue(_type, out var srcActList))
            {
                //检查该类型事件是否拥有回调,无内容直接返回
                if (srcActList != null && srcActList.CallCount == 0)
                    return;
                //从缓存池中获取对象作为副本
                var dealer = m_broadcastActionCache.PopItem();
                if (dealer == null)
                    return;
                try
                {
                    //执行回调
                    dealer.AddCall(srcActList);
                    for (int i = 0; i < dealer.CallCount; i++)
                    {
                        var del = dealer[i];
                        if (del == null)
                            continue;
                        del.Invoke();
                    }
                }
                finally
                {
                    //将使用完的对象返回缓存池
                    m_broadcastActionCache.PushItem(dealer);
                }

            }
            
            //广播消息之后的操作 
            _OnSend();
        }

        protected bool _HasUnregCallback()
        {
            if (m_dActionDic != null && m_dActionDic.Count > 0 && m_dCallBackDic != null && m_dCallBackDic.Count > 0)
            {
                return true;
            }
            return false;
        }

        #region 抽象层
        /// <summary>
        /// 派生对象名字
        /// </summary>
        protected abstract  string DeriveName { get; }
        /// <summary>
        /// 广播消息的后续处理
        /// </summary>
        protected abstract void _OnSend();

        #endregion
    }
}
